library(tidyverse)
library(rlang)
library(lubridate)
library(scales)
library(ggrepel)
library(glue)
library(rvest)
library(pander)
library(plotly)
library(QuantTools)
library(httr)
library(jsonlite)
library(DT)
library(reactable)
library(htmltools)
panderOptions("big.mark", ",")
panderOptions("table.split.table", Inf)
panderOptions("table.style", "rmarkdown")
panderOptions("missing", "")
theme_set(theme_bw())
auStates <- c(
ACT = "Australian Capital Territory",
QLD = "Queensland",
NSW = "New South Wales",
VIC = "Victoria",
SA = "South Australia",
WA = "Western Australia",
NT = "Northern Territory",
TAS = "Tasmania",
AUS = "All States"
)
ausPops <- tribble(
~State, ~Population,
"New South Wales", 8167532,
"Victoria", 6696670,
"Queensland", 5176186,
"Western Australia", 2663561,
"South Australia", 1770375,
"Tasmania", 540780,
"Northern Territory", 246413,
"Australian Capital Territory", 431380
) %>%
bind_rows(
tibble(
State = "All States",
Population = sum(.$Population)
)
)
data <- fromJSON("https://covidlive.com.au/covid-live.json") %>%
as_tibble() %>%
mutate(
across(
.cols = ends_with("CNT"),
.fns = as.numeric
),
REPORT_DATE = ymd(REPORT_DATE),
LAST_UPDATED_DATE = as_datetime(LAST_UPDATED_DATE, tz = Sys.timezone())
)
dt <- data %>%
dplyr::filter(
CODE == "AUS", !is.na(LAST_UPDATED_DATE)
) %>%
pull(REPORT_DATE) %>%
max()
All Data was taken from COVID-Live which is itself taken from the federally reported numbers. Discrepancies between state and federal numbers are common and generally known, however, given that these are the official figures numbers are taken at face value. No manual effort has been undertaken to correct these as that is a potentially endless and overwhelming task. Delays updating individual fields can occur often, such that the reported data is periodically incomplete during the day.
All values are current as of 21:18, 15 Jan 2022
Australian State populations were taken from the ABS Website and were accurate on 1st Jan 2022.
Using an estimated population size of 25,692,897, the total percentage of the Australian population confirmed as having been infected at some point currently sits at 6.38%, or one person in every 16.
addSign <- function(x, .f = comma, .accuracy = 1) {
out <- x
out[is.na(x)] <- ""
out[which(x > 0)] <- paste0("+", .f(x[which(x > 0)], accuracy = .accuracy))
out[which(x <= 0)] <- .f(x[which(x <= 0)], accuracy = .accuracy)
out
}
bar_chart <- function(label, width = "100%", height = "16px", fill = "#00bfc4", background = NULL) {
bar <- div(style = list(background = fill, width = width, height = height))
chart <- div(style = list(flexGrow = 1, marginLeft = "8px", background = background), bar)
div(style = list(display = "flex", alignItems = "left"), label, chart)
}
bar_chart_pos_neg <- function(label, value, max_value = 1, height = "16px",
pos_fill = "#005ab5", neg_fill = "#dc3220") {
neg_chart <- div(style = list(flex = "1 1 0"))
pos_chart <- div(style = list(flex = "1 1 0"))
width <- paste0(abs(value / max_value) * 100, "%")
if (value < 0) {
bar <- div(style = list(marginLeft = "8px", background = neg_fill, width = width, height = height))
chart <- div(style = list(display = "flex", alignItems = "center", justifyContent = "flex-end"), label, bar)
neg_chart <- tagAppendChild(neg_chart, chart)
} else {
bar <- div(style = list(marginRight = "8px", background = pos_fill, width = width, height = height))
chart <- div(style = list(display = "flex", alignItems = "center"), bar, label)
pos_chart <- tagAppendChild(pos_chart, chart)
}
div(style = list(display = "flex"), neg_chart, pos_chart)
}
fs <- "12px"
bar_style <- function(width = 1, fill = "#e6e6e6", height = "75%", align = c("left", "right"), color = NULL) {
align <- match.arg(align)
if (align == "left") {
position <- paste0(width * 100, "%")
image <- sprintf("linear-gradient(90deg, %1$s %2$s, transparent %2$s)", fill, position)
} else {
position <- paste0(100 - width * 100, "%")
image <- sprintf("linear-gradient(90deg, transparent %1$s, %2$s %1$s)", position, fill)
}
list(
backgroundImage = image,
backgroundSize = paste("100%", height),
backgroundRepeat = "no-repeat",
backgroundPosition = "center",
color = color,
fontSize = fs
)
}
hs <- list(fontWeight = "bold", fontSize = fs)
df <- data %>%
dplyr::filter(REPORT_DATE == dt) %>%
dplyr::mutate(
CASE_CNT = ifelse(is.na(CASE_CNT), PREV_CASE_CNT, CASE_CNT),
ACTIVE_CNT = ifelse(is.na(ACTIVE_CNT), PREV_ACTIVE_CNT, ACTIVE_CNT),
`Daily Change` = NEW_CASE_CNT,
`% Change` = `Daily Change` / PREV_ACTIVE_CNT,
State = case_when(
CODE == "AUS" ~ "All States",
TRUE ~ auStates[CODE]
),
State = factor(State, levels = ausPops$State)
) %>%
left_join(ausPops) %>%
mutate(
CODE_UP = ifelse(is.na(LAST_UPDATED_DATE), paste0(CODE, "*"), CODE),
Rate = 1e5 * ACTIVE_CNT / Population,
`% Total` = CASE_CNT / Population,
`% Active` = ACTIVE_CNT / CASE_CNT,
PPI = 1e5/Rate
) %>%
dplyr::select(
State = CODE_UP, CASE_CNT, `% Total`, `% Active`,
ACTIVE_CNT, `Daily Change`, `% Change`, contains("Rate"),
PPI
) %>%
dplyr::arrange(State)
tbl <- df %>%
dplyr::filter(State != "AUS") %>%
reactable(
columns = list(
State = colDef(footer = "Total", maxWidth = 65),
CASE_CNT = colDef(
name = "Total",
cell = function(value) comma(value, 1),
maxWidth = 100,
footer = comma(
dplyr::filter(df, State == "AUS")[["CASE_CNT"]]
)
),
`% Total` = colDef(
name = "% of Population",
cell = function(value) percent(value, 0.1),
footer = percent(
dplyr::filter(df, State == "AUS")[["% Total"]],
0.1
)
),
`% Active` = colDef(
name = "% Currently Active",
format = colFormat(percent = TRUE, digits = 1),
style = function(value) bar_style(width = value),
maxWidth = 100,
align = "right",
footer = percent(
dplyr::filter(df, State == "AUS")[["% Active"]],
0.1
)
),
ACTIVE_CNT = colDef(
name = "Total",
cell = function(value) comma(value, 1),
maxWidth = 100,
footer = comma(
dplyr::filter(df, State == "AUS")[["ACTIVE_CNT"]]
)
),
`Daily Change` = colDef(
cell = function(value) addSign(value),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = addSign(
dplyr::filter(df, State == "AUS")[["Daily Change"]]
)
),
`% Change` = colDef(
cell = function(value) addSign(value, percent, 1),
maxWidth = 90,
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = addSign(
dplyr::filter(df, State == "AUS")[["% Change"]],
percent, 1
)
),
Rate = colDef(
name = "Active Cases per 100,000",
format = colFormat(digits = 0, separators = TRUE),
style = function(value) bar_style(width = 0.5*value/max(df$Rate)),
maxWidth = 90,
align = "right",
# cell = function(value) comma(value, 1),
footer = comma(dplyr::filter(df, State == "AUS")[["Rate"]], 1)
),
PPI = colDef(
name = "People Per Active Case",
cell = function(value) comma(value, 1),
maxWidth = 90,
footer = comma(dplyr::filter(df, State == "AUS")[["PPI"]], 1)
)
),
columnGroups = list(
colGroup(
name = "Cumulative Cases", columns = c("CASE_CNT", "% Total"),
headerStyle = hs
),
colGroup(
name = "Active Cases",
columns = c("% Active", "ACTIVE_CNT", "Daily Change", "% Change"),
headerStyle = hs
),
colGroup(
name = "Infection Rates", columns = c("Rate", "PPI"),
headerStyle = hs
)
),
defaultColDef = colDef(
headerStyle = hs, footerStyle = hs, style = list(fontSize = fs)
)
)
cp <- glue(
"% Active indicates how many of the total cases are currently active. ",
"Importantly, given problems with testing in many states, the number of ",
"active cases will be an underestimate. ",
"States which are yet to report daily numbers are highlighted with an asterisk."
)
div(class = "active-cases",
div(class = "active-cases-header",
h2(class = "active-cases-title", "Summary of Active Infections"),
cp
),
tbl
)
hosp_off <- 7
df <- data %>%
dplyr::filter(REPORT_DATE == dt) %>%
dplyr::mutate(
MED_HOSP_CNT = ifelse(is.na(MED_HOSP_CNT), PREV_MED_HOSP_CNT, MED_HOSP_CNT),
MED_ICU_CNT = ifelse(is.na(MED_ICU_CNT), PREV_MED_ICU_CNT, MED_ICU_CNT),
MED_VENT_CNT = ifelse(is.na(MED_VENT_CNT), PREV_MED_VENT_CNT, MED_VENT_CNT),
State = case_when(
CODE == "AUS" ~ "All States",
TRUE ~ auStates[CODE]
),
State = factor(State, levels = ausPops$State),
CODE_UP = ifelse(is.na(LAST_UPDATED_DATE), paste0(CODE, "*"), CODE)
) %>%
left_join(ausPops, by = "State") %>%
dplyr::select(
CODE, CODE_UP, State, Population,
contains("HOSP"), contains("ICU"), contains("VENT")
) %>%
left_join(
dplyr::filter(data, REPORT_DATE == dt - hosp_off + 1) %>%
dplyr::select(CODE, ACTIVE_CNT),
by = "CODE"
) %>%
mutate(
change_hosp = MED_HOSP_CNT - PREV_MED_HOSP_CNT,
perc_change_hosp = change_hosp / PREV_MED_HOSP_CNT,
total_perc_hosp = MED_HOSP_CNT / ACTIVE_CNT,
change_icu = MED_ICU_CNT - PREV_MED_ICU_CNT,
perc_change_icu = change_icu / PREV_MED_ICU_CNT,
# perc_hosp_icu = MED_ICU_CNT / MED_HOSP_CNT,
perc_hosp_icu = MED_ICU_CNT / PREV_MED_HOSP_CNT,
change_vent = MED_VENT_CNT - PREV_MED_VENT_CNT,
perc_change_vent = change_vent / PREV_MED_VENT_CNT,
# perc_hosp_vent = MED_VENT_CNT / MED_HOSP_CNT,
perc_hosp_vent = MED_VENT_CNT / PREV_MED_HOSP_CNT,
across(
contains("perc"), function(x) {
x[is.nan(x)] <- 0
x[is.infinite(x)] <- NA_real_
x
}
)
) %>%
dplyr::select(
State = CODE_UP, hospitalised = MED_HOSP_CNT,
ends_with("hosp"), contains("icu"), contains("vent"),
-starts_with("PREV")
) %>%
arrange(State) %>%
split(f = .$State == "AUS") %>%
setNames(c("states", "national"))
tbl <- df$states %>%
reactable(
columns = list(
State = colDef(footer = "Total", maxWidth = 60),
hospitalised = colDef(
name = "Total",
cell = function(value) comma(value, 1),
maxWidth = 80,
footer = comma(df$national$hospitalised)
),
change_hosp = colDef(
name = "Change",
cell = function(value) addSign(value),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
maxWidth = 80,
footer = addSign(df$national$change_hosp)
),
perc_change_hosp = colDef(
name = "% Change",
maxWidth = 80,
cell = function(value) percent(value, 0.1),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = percent(df$national$perc_change_hosp, 0.1)
),
total_perc_hosp = colDef(
name = "% Cases (Offset)",
maxWidth = 80,
format = colFormat(digits = 1, percent = TRUE),
style = function(value) bar_style(width = value , fill = "#C53270"),
align = "right",
footer = percent(df$national$perc_hosp_vent, 0.1)
),
MED_ICU_CNT = colDef(
name = "Total",
maxWidth = 60,
cell = function(value) comma(value, 1),
footer = comma(df$national$MED_ICU_CNT)
),
change_icu = colDef(
name = "Change",
maxWidth = 80,
cell = function(value) addSign(value),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = addSign(df$national$change_icu)
),
perc_change_icu = colDef(
name = "% Change",
maxWidth = 80,
cell = function(value) percent(value, 0.1),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = percent(df$national$perc_change_icu, 0.1)
),
perc_hosp_icu = colDef(
name = "% Of Hosp.",
maxWidth = 75,
format = colFormat(digits = 1, percent = TRUE),
style = function(value) bar_style(width = value*2, fill = "#F69422"),
align = "right",
footer = percent(df$national$perc_hosp_icu, 0.1)
),
MED_VENT_CNT = colDef(
name = "Total",
maxWidth = 70,
cell = function(value) comma(value, 1),
footer = comma(df$national$MED_VENT_CNT)
),
change_vent = colDef(
name = "Change",
maxWidth = 80,
cell = function(value) addSign(value),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = addSign(df$national$change_vent)
),
perc_change_vent = colDef(
name = "% Change",
maxWidth = 80,
cell = function(value) percent(value, 0.1),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = percent(df$national$perc_change_vent, 0.1)
),
perc_hosp_vent = colDef(
name = "% Of Hosp.",
maxWidth = 75,
format = colFormat(digits = 1, percent = TRUE),
style = function(value) bar_style(width = value *2, fill = "#FFFE9E"),
align = "right",
footer = percent(df$national$perc_hosp_vent, 0.1)
)
),
columnGroups = list(
colGroup(
name = "Hospitalised", columns = str_subset(colnames(df$states), "(^hosp|hosp$)"),
headerStyle = hs
),
colGroup(
name = "ICU", columns = str_subset(colnames(df$states), "ICU|icu"),
headerStyle = hs
),
colGroup(
name = "Ventilated", str_subset(colnames(df$states), "VENT|vent"),
headerStyle = hs
)
),
defaultColDef = colDef(
footerStyle = hs, headerStyle = hs, style = list(fontSize = fs)
)
)
cp <- glue(
"The % Cases Hospitalised column uses active cases with a {hosp_off} day ",
"offset and as such is a crude estimate. This is confounded by the ",
"difference in lag between exposure and hospitalisation for each strain. ",
"The % of currently hospitlised cases which are in ICU or being ventilated ",
"is also given, using a 1-day offset. ",
"Figures from the NT are as reported federally and these are highly ",
"divergent from state-reported figures. The reason for this is unknown. ",
"States which are yet to report are indicated with an asterisk. "
)
div(class = "hospitalisations",
div(class = "hospitalisations-header",
h2(class = "hospitalisations-title", "Summary of hospitalisations"),
cp
),
tbl
)
death_off <- 14
df <- data %>%
dplyr::filter(REPORT_DATE == dt) %>%
dplyr::mutate(
State = case_when(
CODE == "AUS" ~ "All States",
TRUE ~ auStates[CODE]
),
State = factor(State, levels = ausPops$State),
CODE_UP = ifelse(is.na(LAST_UPDATED_DATE), paste0(CODE, "*"), CODE),
CASE_CNT = ifelse(is.na(CASE_CNT), PREV_CASE_CNT, CASE_CNT),
DEATH_CNT = ifelse(is.na(DEATH_CNT), PREV_DEATH_CNT, DEATH_CNT),
) %>%
left_join(ausPops, by = "State") %>%
dplyr::select(CODE, CODE_UP, State, contains("DEATH"), `Total Cases` = CASE_CNT) %>%
left_join(
data %>%
dplyr::filter(REPORT_DATE == dt - death_off + 1) %>%
dplyr::select(CODE, CASE_CNT)
) %>%
mutate(
`Daily Fatalities` = DEATH_CNT - PREV_DEATH_CNT,
`Fatality Rate` = DEATH_CNT / CASE_CNT
) %>%
dplyr::select(
State = CODE_UP, `Total Cases`, `Total Fatalities` = DEATH_CNT, contains("Fatal")
) %>%
split(.$State == "AUS") %>%
setNames(c("states", "national"))
tbl <- df$states %>%
reactable(
columns = list(
State = colDef(maxWidth = 80, footer = "Total"),
`Total Cases` = colDef(
format = colFormat(separators = TRUE),
footer = comma(df$national$`Total Cases`)
),
`Total Fatalities` = colDef(
format = colFormat(separators = TRUE),
footer = comma(df$national$`Total Fatalities`)
),
`Daily Fatalities` = colDef(
format = colFormat(separators = TRUE),
cell = function(value) addSign(value),
style = function(value) {
color <- case_when(
is.na(value) ~ "white",
value > 0 ~ "#e00000",
value < 0 ~ "#008000",
TRUE ~ "black"
)
wt <- ifelse(value == 0, 400, 600)
list(fontWeight = wt, color = color, fontSize = fs)
},
footer = comma(df$national$`Daily Fatalities`)
),
`Fatality Rate` = colDef(
format = colFormat(percent = TRUE, digits = 1),
style = function(value) bar_style(width = 3*value),
footer = percent(df$national[["Fatality Rate"]], 0.1)
)
),
defaultColDef = colDef(footerStyle = hs, headerStyle = hs, style = list(fontSize = fs))
)
cp <- glue(
"Summary of fatalities since the beginning of the pandemic. ",
"The fatality rate is calculated using the total cases offset by {death_off} days."
)
div(class = "fatalities",
div(class = "fatalities-header",
h2(class = "fatalities-title", "Summary of Fatalities"),
cp
),
tbl
)
plotly::ggplotly(
data %>%
dplyr::mutate(
State = case_when(
CODE == "AUS" ~ "All States",
TRUE ~ auStates[CODE]
),
State = factor(State, levels = ausPops$State)
) %>%
left_join(ausPops) %>%
mutate(
State = factor(State, levels = ausPops$State),
`% Active` = percent(ACTIVE_CNT / Population, 0.01),
Active = comma(ACTIVE_CNT, accuracy = 1)
) %>%
dplyr::rename(Date = REPORT_DATE) %>%
ggplot(
aes(label = `% Active`, key = Active, group = 1)
) +
geom_line(
aes(Date, ACTIVE_CNT / Population, colour = State)
) +
coord_cartesian(xlim = c(dt - 1.5*365, dt)) +
scale_y_continuous(labels = percent, trans = "sqrt") +
scale_colour_brewer(palette = "Set1") +
labs(
x = "Date", y = "% Of Population Currently Infected"
),
tooltip = c("State", "Date", "% Active", "Active")
) %>%
plotly::style(visible = "legendonly", traces = c(6:9))
Plot of active infections against time for the last year. Double-click on a state in the legend to only see that state, or single-click individually to add or remove.
inc <- 6
icu <- 11
d <- 7
offset <- icu + d
minDate <- "2020-04-20"
df <- list(
data %>%
dplyr::filter(CODE == "AUS", REPORT_DATE > minDate) %>%
dplyr::select(date = REPORT_DATE, confirmed = CASE_CNT, deaths = DEATH_CNT) %>%
arrange(date) %>%
mutate(fr = deaths / confirmed, type = "No Offset"),
data %>%
dplyr::filter(CODE == "AUS") %>%
dplyr::select(date = REPORT_DATE, confirmed = CASE_CNT, deaths = DEATH_CNT) %>%
arrange(date) %>%
mutate(
confirmed = c(rep(NA, offset), confirmed[seq_len(nrow(.) - offset)]),
fr = deaths / confirmed,
type = glue("Offset ({offset} days)")
) %>%
dplyr::filter(date > minDate)
) %>%
bind_rows() %>%
left_join(
dplyr::filter(data, CODE == "AUS") %>%
dplyr::select(date = REPORT_DATE, VACC_FIRST_DOSE_CNT)
) %>%
mutate(
vacc = VACC_FIRST_DOSE_CNT / max(ausPops$Population),
vacc_scaled = vacc * max(fr)
)
df %>%
ggplot(
aes(date, fr, colour = type)
) +
geom_line() +
geom_line(
aes(date, y = vacc_scaled),
data = . %>%
dplyr::filter(type == "No Offset", vacc > 0),
inherit.aes = FALSE,
colour = "red"
) +
geom_label_repel(
aes(label = percent(fr, 0.1)),
data = . %>% dplyr::filter(date == max(date), type != "No Offset"),
size = 3.5, show.legend = FALSE
) +
geom_label_repel(
aes(y = vacc_scaled, label = percent(vacc, 0.1)),
data = . %>% dplyr::filter(date == max(date), type != "No Offset"),
colour = "red", size = 3.5, show.legend = FALSE
) +
scale_x_date(
expand = expansion(mult = 0, add = 20)
) +
scale_y_continuous(
label = percent,
sec.axis = sec_axis(
~ (.) / max(df$fr), labels = percent, name = "% Population >= 1 Dose"
)
) +
scale_colour_brewer(palette = "Paired") +
labs(
x = "Date",
y = "Estimated Fatality Rate",
colour = "Calculation"
) +
theme(
axis.title.y.right = element_text(colour = "red"),
axis.text.y.right = element_text(colour = "red"),
axis.ticks.y.right = element_line(colour = "red")
)
Fatality rate for Australian cases as calculated using two methods. Where no offset is included, the rate shown is simply the number of fatalities divided by the total number of reported cases on the same date. When cases increase during a new outbreak, this will skew the fatality rate lower. An alternative is to use an offset based on the fact the the median time from infection to symptom onset is 6 days, the median time from symptom onset to ICU admission is 11 days, and the median time from ICU admission to mortality is 7 days. When using the offset, the fatality rate is calculated as the number of recorded fatalities on a given date, divided by by the number of cases from 18 days ago. Whilst still flawed this may give a less biased estimate on the true fatality rate, and importantly, will always be higher than the alternative calculation. The intial fatality rate spiked above 30% during the intial outbreak under the offset approach, and as such, data is only shown after 20 Apr, 2020. The red line indicates the proportaion of the total Australian population which has received at least one vaccine dose. All times used for estimation the offset were obtained from here
plotly::ggplotly(
data %>%
dplyr::filter(CASE_CNT > 100) %>%
dplyr::select(ends_with("DATE"), CODE, contains("TEST"), NEW_CASE_CNT) %>%
mutate(
NEW_CASE_CNT = ifelse(is.na(NEW_CASE_CNT), 0, NEW_CASE_CNT),
TEST_CNT = ifelse(is.na(TEST_CNT), PREV_TEST_CNT, TEST_CNT),
Tests = TEST_CNT - PREV_TEST_CNT,
PR = NEW_CASE_CNT / Tests,
PR = case_when(
is.nan(PR) ~ NA_real_,
is.infinite(PR) ~ NA_real_,
PR > 1 ~ NA_real_,
PR < 0 ~ NA_real_,
TRUE ~ PR
),
State = case_when(
CODE == "AUS" ~ "All States",
TRUE ~ auStates[CODE]
),
State = factor(State, levels = ausPops$State),
`Test Positivity` = percent(PR, 0.01)
) %>%
dplyr::rename(Date = REPORT_DATE) %>%
ggplot(
aes(Date, PR, colour = State, label = `Test Positivity`)
) +
geom_line() +
geom_hline(yintercept = 0.05, linetype = 2) +
coord_cartesian(xlim = c(dt - 180, dt)) +
scale_colour_brewer(palette = "Set1") +
scale_y_continuous(labels = percent) +
labs(x = "Test Positivity Rate"),
tooltip = c("Date", "State", "Test Positivity")
) %>%
plotly::style(visible = "legendonly", traces = c(6:9))
Test Positivity Rate. A single click in the plot legend will show/hide that State. The 5% rate, below which the pandemic is considered manageable by the WHO is shown as a dashed line.
R version 4.1.2 (2021-11-01)
Platform: x86_64-pc-linux-gnu (64-bit)
locale: LC_CTYPE=C, LC_NUMERIC=C, LC_TIME=C, LC_COLLATE=C, LC_MONETARY=C, LC_MESSAGES=en_AU.UTF-8, LC_PAPER=en_AU.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_AU.UTF-8 and LC_IDENTIFICATION=C
attached base packages: stats, graphics, grDevices, utils, datasets, methods and base
other attached packages: htmltools(v.0.5.2), reactable(v.0.2.3), DT(v.0.20), jsonlite(v.1.7.2), httr(v.1.4.2), QuantTools(v.0.5.7.1), data.table(v.1.14.2), plotly(v.4.10.0), pander(v.0.6.4), rvest(v.1.0.2), glue(v.1.6.0), ggrepel(v.0.9.1), scales(v.1.1.1), lubridate(v.1.8.0), rlang(v.0.4.12), forcats(v.0.5.1), stringr(v.1.4.0), dplyr(v.1.0.7), purrr(v.0.3.4), readr(v.2.1.1), tidyr(v.1.1.4), tibble(v.3.1.6), ggplot2(v.3.3.5) and tidyverse(v.1.3.1)
loaded via a namespace (and not attached): sass(v.0.4.0), viridisLite(v.0.4.0), modelr(v.0.1.8), bslib(v.0.3.1), fasttime(v.1.0-2), assertthat(v.0.2.1), highr(v.0.9), cellranger(v.1.1.0), yaml(v.2.2.1), pillar(v.1.6.4), backports(v.1.4.1), digest(v.0.6.29), RColorBrewer(v.1.1-2), colorspace(v.2.0-2), reactR(v.0.4.4), pkgconfig(v.2.0.3), broom(v.0.7.10), haven(v.2.4.3), tzdb(v.0.2.0), generics(v.0.1.1), farver(v.2.1.0), ellipsis(v.0.3.2), withr(v.2.4.3), lazyeval(v.0.2.2), cli(v.3.1.0), magrittr(v.2.0.1), crayon(v.1.4.2), readxl(v.1.3.1), evaluate(v.0.14), fs(v.1.5.2), fansi(v.0.5.0), xml2(v.1.3.3), tools(v.4.1.2), hms(v.1.1.1), lifecycle(v.1.0.1), munsell(v.0.5.0), reprex(v.2.0.1), compiler(v.4.1.2), jquerylib(v.0.1.4), grid(v.4.1.2), rstudioapi(v.0.13), htmlwidgets(v.1.5.4), crosstalk(v.1.2.0), labeling(v.0.4.2), rmarkdown(v.2.11), gtable(v.0.3.0), DBI(v.1.1.1), curl(v.4.3.2), R6(v.2.5.1), knitr(v.1.37), fastmap(v.1.1.0), utf8(v.1.2.2), stringi(v.1.7.6), Rcpp(v.1.0.7), vctrs(v.0.3.8), dbplyr(v.2.1.1), tidyselect(v.1.1.1) and xfun(v.0.29)